#include "TCPSocket.h"



CTCPSocket::CTCPSocket(ReadFunction cb, LPVOID argv, std::string ip, USHORT port) : mReadFunction(cb), mConnected(FALSE), mIp(ip), mPort(port),
mIsAlive(FALSE), mArgv(argv)
{
}

CTCPSocket::CTCPSocket(SOCKET sock, ReadFunction cb, LPVOID argv) : mReadFunction(cb), mConnected(TRUE), mIsAlive(FALSE),
mArgv(argv), mSocket(sock)
{
}

CTCPSocket::~CTCPSocket()
{
	if (mConnected) {
		closesocket(mSocket);
	}
}

BOOL CTCPSocket::Start()
{
	if (!mReadFunction)
		return FALSE;
	if (mConnected == FALSE) {
		mSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
		SOCKADDR_IN sin;
		sin.sin_family = AF_INET;
		sin.sin_addr.s_addr = inet_addr(mIp.c_str());
		sin.sin_port = htons(mPort);
		if (connect(mSocket, (struct sockaddr*)&sin, sizeof(sin)) < 0) {
			return FALSE;
		}
		mConnected = TRUE;
	}
	mIsAlive = TRUE;
	mThread = new std::thread(ThreadFunction, this);
	if (!mThread) {
		closesocket(mSocket);
		return FALSE;
	}
	return TRUE;
}

void CTCPSocket::Stop()
{
	mIsAlive = FALSE;
	closesocket(mSocket);
	if (mThread) {
		mThread->detach();
		mThread = NULL;
	}
}

int CTCPSocket::Write(char*buf, long buflen)
{
	if (!mIsAlive) {
		return -1;
	}
	return send(mSocket, buf, buflen, 0);
}

void CTCPSocket::ThreadFunction(LPVOID argv)
{
	CTCPSocket* mThis = reinterpret_cast<CTCPSocket*>(argv);
	if (!mThis)
		return;

#define IBUFFSIZE 2048
	char buff[IBUFFSIZE] = { 0 };

	WSAEVENT nEvent = ::WSACreateEvent();
	WSAEventSelect(mThis->mSocket, nEvent, FD_READ | FD_CLOSE);//FD_WRITE
	while (mThis->mIsAlive) {
		int ret = WaitForSingleObject(nEvent, 60 * 1000);
		if (ret != WSA_WAIT_EVENT_0) {
			break;
		}

		WSANETWORKEVENTS ne;
		WSAEnumNetworkEvents(mThis->mSocket, nEvent, &ne);
		WSAResetEvent(nEvent);
		if (ne.lNetworkEvents & FD_CLOSE) {
			if (ne.iErrorCode[FD_CLOSE_BIT] != 0)
			{
				//printf("FD_CLOSE failed with error %d\n", ne.iErrorCode[FD_CLOSE_BIT]);
				break;
			}
			break;
		}
		if (ne.lNetworkEvents &FD_READ) {
			if (ne.iErrorCode[FD_READ_BIT] != 0)
			{
				printf("FD_READ failed with error %d\n", ne.iErrorCode[FD_READ_BIT]);
				break;
			}
			int len = recv(mThis->mSocket, buff, IBUFFSIZE, 0);
			if (len < 0) {
				break;
			}
			if (mThis->mReadFunction(buff, len, mThis->mArgv) < 0) {
				break;
			}
		}
	}
Finish:
	mThis->mIsAlive = FALSE;
	::closesocket(mThis->mSocket);
	::WSACloseEvent(nEvent);
	return;
}
